using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using CalcSharp.Core.General;

namespace CalcSharp.Core.Containers
{
    /// <summary>
    /// Floating Point Memory Data Class
    /// </summary>
    [Serializable]
    [StructLayout(LayoutKind.Sequential)]
    public class Data
    {
        public string desc;
        public double value;
    }

    /// <summary>
    /// Floating Point memory Manager Class
    /// </summary>
    public class FloatManager : IMemMan<Data, double>
    {
        private Dictionary<string, double> Engine;
        public FloatManager()
        {
            Engine = new Dictionary<string, double>();
        }

        /// <summary>
        /// Gets the set variable names
        /// </summary>
        public string[] keys
        {
            get
            {
                return Engine.Keys.ToArray();
            }
        }

        /// <summary>
        /// Packs a single variable for serializazion
        /// </summary>
        /// <param name="index">the variable's name</param>
        /// <returns>the packed variable</returns>
        public Data PackSingle(string name)
        {
            if (string.IsNullOrEmpty(name)) throw new ArgumentException("Name can't be null");
            name = name.ToLower();
            Data ret = new Data();
            ret.value = Engine[name];
            ret.desc = name;
            return ret;
        }

        /// <summary>
        /// Adds a Data item to the memory
        /// </summary>
        /// <param name="item">The item to be added</param>
        /// <returns>the number of elements in the memory</returns>
        public int Add(Data item)
        {
            if (Engine.ContainsKey(item.desc)) Engine[item.desc] = item.value;
            else  Engine.Add(item.desc, item.value);
            return Engine.Count;
        }
        /// <summary>
        /// the number of elements in the memory
        /// </summary>
        public int Count
        {
            get { return Engine.Count; }
        }
        /// <summary>
        /// Clears thhe memory
        /// </summary>
        public void Clear()
        {
            this.Engine.Clear();
        }
        /// <summary>
        /// Gets or sets a double value based on a variable name
        /// </summary>
        /// <param name="name">The variable name</param>
        /// <returns>The number which is stored under the name</returns>
        public double this[string name]
        {
            get
            {
                name = name.ToLower(CultureInfo.CurrentCulture);
                string test = Regex.Replace(name, Patterns.Float, "-ok-");
                if (test != "-ok-") throw new CSException("Incorrect variable name!");
                double val = 0.0;
                if (this.Engine.ContainsKey(name)) val = Engine[name];
                return val;
            }
            set
            {
                name = name.ToLower(CultureInfo.CurrentCulture);
                string test = Regex.Replace(name, Patterns.Float, "-ok-");
                if (test != "-ok-") throw new CSException("Incorrect variable name: " + name);
                if (MiscCoreFuncts.protectedconstant(name)) throw new CSException("This is a protected constant! Choose another name!");
                if (this.Engine.ContainsKey(name)) this.Engine[name] = value;
                else this.Engine.Add(name, value);
            }
        }
        /// <summary>
        /// Tells wheather a variable name is used or not
        /// </summary>
        /// <param name="name">the variable name</param>
        /// <returns>true, if set, false if not</returns>
        public bool isset(string name)
        {
            return Engine.ContainsKey(name.ToLower());
        }
        /// <summary>
        /// delets a variable
        /// </summary>
        /// <param name="name">the variable name</param>
        public void unset(string name)
        {
            string test = Regex.Replace(name, Patterns.Float, "-ok-");
            if (test != "-ok-") throw new CSException("Incorrect variable name: " + name);
            Engine.Remove(name.ToLower());
        }
    }
}